package com.itgaohe.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itgaohe.common.context.UserContext;
import com.itgaohe.dao.entity.Follow;
import com.itgaohe.dao.entity.User;
import com.itgaohe.dao.entity.UserInfo;
import com.itgaohe.dao.mapper.FollowMapper;
import com.itgaohe.dao.mapper.UserInfoMapper;
import com.itgaohe.dao.mapper.UserMapper;
import com.itgaohe.dto.UserDTO;
import com.itgaohe.dto.requ.LoginRequestDTO;
import com.itgaohe.dto.resp.CursorResponseDTO;
import com.itgaohe.dto.resp.SearchUserInfo;
import com.itgaohe.service.UserService;
import com.itgaohe.utils.CreateCursorUtil;
import com.itgaohe.utils.RegexUtils;
import com.itgaohe.utils.Result;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import static com.itgaohe.common.constant.RedisConstants.*;
import static com.itgaohe.common.constant.UserConstant.USER_NICK_NAME_PREFIX;
import static com.itgaohe.common.constant.UserConstant.UUSER_COMMON_ICON;

@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private FollowMapper followMapper;

    @Override
    public Result sendCode(String phone) {
        // 1.校验手机号
        if (RegexUtils.isPhoneInvalid(phone)) {
            // 2.如果不符合，返回错误信息
            return Result.fail("手机号格式错误！");
        }
        // 3.符合，生成验证码
        String code = RandomUtil.randomNumbers(6);

        // 4.保存验证码到 session
        stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);

        // 5.发送验证码
        log.debug("发送短信验证码成功，验证码：{}", code);
        // 返回ok
        return Result.ok();
    }

    @Override
    public Result login(LoginRequestDTO requestParam) {
        // 1.校验手机号
        String phone = requestParam.getPhone();
        if (RegexUtils.isPhoneInvalid(phone)) {
            // 2.如果不符合，返回错误信息
            return Result.fail("手机号格式错误！");
        }
        // 3.从redis获取验证码并校验
        String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);
        String code = requestParam.getCode();
        if (cacheCode == null || !cacheCode.equals(code)) {
            // 不一致，报错
            return Result.fail("验证码错误");
        }
        // 4.一致，根据手机号查询用户 select * from tb_user where phone = ?
        User user = query().eq("phone", phone).one();

        // 5.判断用户是否存在
        if (user == null) {
            // 6.不存在，创建新用户并保存
            User build = User.builder()
                    .phone(phone)
                    .nickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(5))
                    .updateTime(LocalDateTime.now())
                    .icon(UUSER_COMMON_ICON)
                    .createTime(LocalDateTime.now())
                    .cursorIndex(CreateCursorUtil.getNormalCursor(0L))
                    .build();
            int insert = userMapper.insert(build);
            if (insert <= 0) {
                return Result.fail("登入失败") ;
            }
            user = build ;
        }

        // 7.保存用户信息到 redis中
        // 7.1.随机生成token，作为登录令牌
        String token = UUID.randomUUID().toString(true);
        // 7.2.将User对象转为HashMap存储
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
        Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
                CopyOptions.create()
                        .setIgnoreNullValue(true)
                        .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
        // 7.3.存储
        String tokenKey = LOGIN_USER_KEY + token;
        stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
        // 7.4.设置token有效期
        stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES);
        // 8.返回token
        return Result.ok(token);
    }

    //用户登出
    @Override
    public Result logout(HttpServletRequest request) {

        String token = request.getHeader("authorization");

        String key  = LOGIN_USER_KEY + token;

        try {
            stringRedisTemplate.delete(key);

            UserContext.removeUser();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return Result.ok("登出成功");
    }


    //根据用户id查询所有粉丝
    @Override
    public Result findAllFansByUserId(Long userId,Long cursor) {
        //初始化，如果cursor为1，则进行初始化
        if (cursor == 1) {
            cursor = CreateCursorUtil.initCursor() ;
        }
        //创建dto对象用于封装分页查询的结果
        CursorResponseDTO<SearchUserInfo> cursors = new CursorResponseDTO<>() ;
        //默认有更多的代码可供使用
        cursors.setHasMore(true);
        //调用mapper的方法进行查询
        List<SearchUserInfo> searchUserInfos = userMapper.selectAllFansByUserId(userId, cursor);
        if(searchUserInfos == null || searchUserInfos.size() == 0){
            cursors.setHasMore(false);
            return Result.ok(cursors);
        }
        //遍历查询到的关注用户列表，判断当前登录用户是否关注了每一个用户，并设置关注状态 isFollow
        for (SearchUserInfo searchUserInfo : searchUserInfos) {
            LambdaQueryWrapper<Follow> eq = Wrappers.lambdaQuery(Follow.class)
                    .eq(Follow::getUserId, searchUserInfo.getId())
                    .eq(Follow::getFollowUserId, UserContext.getUser().getId());
            Follow follow = followMapper.selectOne(eq);
            if (BeanUtil.isEmpty(follow)) {
                searchUserInfo.setIsFollow(1);
            } else {
                searchUserInfo.setIsFollow(0);
            }
        }
        //从当前查询结果的最后一条记录中获取 cursorIndex，用于作为下一次分页查询的起始位置（游标），实现分页加载更多数据的功能。
        Long nextCursor = searchUserInfos.get(searchUserInfos.size() - 1).getCursorIndex() ;
        if (searchUserInfos.size() <  10) {
            cursors.setHasMore(false);
        }
        cursors.setNextCursor(nextCursor);
        cursors.setData(searchUserInfos);
        return Result.ok(cursors);
    }

    //根据用户id查询所有关注
    @Override
    public Result findAllFollowersByUserId(Long userId,Long cursor) {
        //初始化，如果cursor为1，则进行初始化
        if (cursor == 1) {
            cursor = CreateCursorUtil.initCursor() ;
        }
        //创建dto对象用于封装分页查询的结果
        CursorResponseDTO<SearchUserInfo> cursors = new CursorResponseDTO<>() ;
        //默认有更多的代码可供使用
        cursors.setHasMore(true);
        //调用mapper的方法进行查询
        List<SearchUserInfo> searchUserInfos = userMapper.selectAllFollowersByUserId(userId, cursor);
        if(searchUserInfos==null|| searchUserInfos.size() == 0){
            cursors.setHasMore(false);
            return Result.ok(cursors);
        }
        //遍历查询到的关注用户列表，判断当前登录用户是否关注了每一个用户，并设置关注状态 isFollow
        for (SearchUserInfo searchUserInfo : searchUserInfos) {
            LambdaQueryWrapper<Follow> eq = Wrappers.lambdaQuery(Follow.class)
                    .eq(Follow::getUserId, searchUserInfo.getId())
                    .eq(Follow::getFollowUserId, UserContext.getUser().getId());
            Follow follow = followMapper.selectOne(eq);
            if (BeanUtil.isEmpty(follow)) {
                searchUserInfo.setIsFollow(1);
            } else {
                searchUserInfo.setIsFollow(0);
            }
        }
        //从当前查询结果的最后一条记录中获取 cursorIndex，用于作为下一次分页查询的起始位置（游标），实现分页加载更多数据的功能。
        Long nextCursor = searchUserInfos.get(searchUserInfos.size() - 1).getCursorIndex() ;
        if (searchUserInfos.size() <  10) {
            cursors.setHasMore(false);
        }
        cursors.setNextCursor(nextCursor);
        cursors.setData(searchUserInfos);
        return Result.ok(cursors);
    }

    // 根据用户id查询用户详细信息
    @Override
    public List<UserInfo> findAllUserInfoByUserId(Long userId) {
        List<UserInfo> userInfoList = userMapper.selectAllUserInfoByUserId(userId);
        return userInfoList;
    }

    //根据用户昵称搜索用户
    @Override
    public Result searchUsersByNickName(String nickName, Long cursor) {
        if (cursor == 1) {
            cursor = CreateCursorUtil.initCursor() ;
        }
        CursorResponseDTO<SearchUserInfo> cursors = new CursorResponseDTO<>() ;
        cursors.setHasMore(true);
        List<SearchUserInfo> searchUserInfos = userMapper.searchUsersByNickName(nickName, cursor);
        if (searchUserInfos == null || searchUserInfos.isEmpty()){
            cursors.setHasMore(false);
            return Result.ok(cursors);
        }
        for (SearchUserInfo searchUserInfo : searchUserInfos) {
            LambdaQueryWrapper<Follow> eq = Wrappers.lambdaQuery(Follow.class)
                    .eq(Follow::getUserId, searchUserInfo.getId())
                    .eq(Follow::getFollowUserId, UserContext.getUser().getId());
            Follow follow = followMapper.selectOne(eq);
            if (BeanUtil.isEmpty(follow)) {
                searchUserInfo.setIsFollow(1);
            } else {
                searchUserInfo.setIsFollow(0);
            }
        }
        Long nextCursor = searchUserInfos.get(searchUserInfos.size() - 1).getCursorIndex() ;
        if (searchUserInfos.size() <  10) {
            cursors.setHasMore(false);
        }
        cursors.setNextCursor(nextCursor);
        cursors.setData(searchUserInfos);
        return Result.ok(cursors);
    }
    @Override
    public Result searchUsersFriends(Long cursor) {
        //初始化，如果cursor为1，则进行初始化
        if (cursor == 1) {
            cursor = CreateCursorUtil.initCursor() ;
        }
        //创建dto对象用于封装分页查询的结果
        CursorResponseDTO<SearchUserInfo> cursors = new CursorResponseDTO<>() ;
        //默认有更多的代码可供使用
        cursors.setHasMore(true);
        //调用mapper的方法进行查询
        Long userId = UserContext.getUser().getId();
        List<SearchUserInfo> searchUserInfos = userMapper.selectAllFriendsByUserId(userId, cursor);
        if(searchUserInfos==null|| searchUserInfos.size() == 0){
            cursors.setHasMore(false);
            return Result.ok(cursors);
        }
        //遍历查询到的关注用户列表，判断当前登录用户是否关注了每一个用户，并设置关注状态 isFollow
        for (SearchUserInfo searchUserInfo : searchUserInfos) {
            LambdaQueryWrapper<Follow> eq = Wrappers.lambdaQuery(Follow.class)
                    .eq(Follow::getUserId, searchUserInfo.getId())
                    .eq(Follow::getFollowUserId, UserContext.getUser().getId());
            Follow follow = followMapper.selectOne(eq);
            if (BeanUtil.isEmpty(follow)) {
                searchUserInfo.setIsFollow(1);
            } else {
                searchUserInfo.setIsFollow(0);
            }
        }
        //从当前查询结果的最后一条记录中获取 cursorIndex，用于作为下一次分页查询的起始位置（游标），实现分页加载更多数据的功能。
        Long nextCursor = searchUserInfos.get(searchUserInfos.size() - 1).getCursorIndex() ;
        if (searchUserInfos.size() <  10) {
            cursors.setHasMore(false);
        }
        cursors.setNextCursor(nextCursor);
        cursors.setData(searchUserInfos);
        return Result.ok(cursors);
    }

    //查询用户详情
    public Result getMe(){

        Long id = UserContext.getUser().getId();

        UserInfo userInfo = userInfoMapper.selectById(id);

        return Result.ok(userInfo);
    }

    /**
     *
     * @param userId
     * @param isFollow
     * @return
     */
    @Override
    public Result toFollow(Long userId, Integer isFollow) {

        // 获取当前用户ID
        Long followUserId = UserContext.getUser().getId();

        // 获取当前用户
        User followUser = userMapper.selectById(followUserId);

        // 获取所关注用户
        User user = userMapper.selectById(userId);

        // 获取当前用户关注量
        Integer followee = followUser.getFollowee();

        // 更新所关注用户粉丝量
        Integer fans = user.getFans();

        // 构建查询条件：当前用户是否关注目标用户
        LambdaQueryWrapper<Follow> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(Follow::getUserId, userId)
                .eq(Follow::getFollowUserId, followUserId);

        // 查询是否已关注
        Follow follow = followMapper.selectOne(queryWrapper);

        if (isFollow == 0) { // 去关注

            if (follow == null) { // 未关注:进行关注

                try {
                    // 插入新记录
                    Follow insertFollow = new Follow();
                    insertFollow.setUserId(userId);
                    insertFollow.setFollowUserId(followUserId);
                    followMapper.insert(insertFollow);

                    //增加当前用户关注量
                    followUser.setFollowee(followee + 1);

                    //增加所关注用户粉丝量
                    user.setFans(fans + 1);

                    //进行更新操作
                    userMapper.updateById(user);
                    userMapper.updateById(followUser);

                } catch (Exception e) {
                    throw new RuntimeException(e);
                }

                return Result.ok("关注成功!");

            } else { //已关注
                return Result.fail("已关注!!!");
            }
        } else if (isFollow == 1) { // 去取关
            if (follow != null) {
                // 已关注时删除记录
                int value = 0;
                try {

                    value = followMapper.delete(queryWrapper);

                    // 减少用户关注量
                    followUser.setFollowee(followee - 1);

                    // 减少所关注用户粉丝量
                    user.setFans(fans - 1);

                    // 进行更新操作
                    userMapper.updateById(user);
                    userMapper.updateById(followUser);

                } catch (Exception e) {
                    throw new RuntimeException(e);
                }

                if (value > 0) {
                    return Result.ok("取关成功");
                }

            } else { //未关注
                return Result.fail("未关注，无需取关");
            }
        }

        return Result.fail("操作失败");
    }

}
